class MyPromise {
  constructor(fun) {
    //三种状态类型
    this.PENDING = 0;
    this.FULFILLED = 1;
    this.REJECTED = 2;
    this.result = null; // 状态转移时设置好的要传递的值
    this.status = this.PENDING; // 初始化状态
    this.onFulfilledCallbacks = []; // 存储PENDING状态时添加的回调函数
    this.onRejectedCallbacks = []; // 存储PENDING状态时添加的回调函数

    // this 指针的问题，所以这两个函数在这里声明
    this.resolve = (value) => {
      if (this.status == this.PENDING) {
        this.result = value;
        this.status = this.FULFILLED;
        this.onFulfilledCallbacks.forEach((callback) => callback(value));
      }
    };
    this.reject = (reason) => {
      if (this.status == this.PENDING) {
        this.result = reason;
        this.status = this.REJECTED;
        this.onRejectedCallbacks.forEach((callback) => callback(reason));
      }
    };
    this.then = this.then.bind(this); // 绑定this指针，防止函数体内部的this指向的错误
    this.catch = this.catch.bind(this); // 绑定this指针，防止函数体内部的this指向的错误
    try {
      fun.call(this, this.resolve, this.reject);
    } catch (e) {
      this.reject(e);
    }
  }
  then(onfulfilled, onrejected) {
    if (typeof onfulfilled !== "function") {
      onfulfilled = (value) => {
        return value;
      };
    }
    if (typeof onrejected !== "function") {
      onrejected = (reason) => {
        throw reason;
      };
    }
    let realOnFulfilled = onfulfilled;
    let realOnRejected = onrejected;

    switch (this.status) {
      case this.PENDING:
        // PENDING状态.不知道this未来状态的转移，new的resPromise要根据this的状态转移而转移。
        let resPromise = new MyPromise((resolve, reject) => {
          // 只有PENDING状态才会处理队列，所以PENDING状态要push回调
          this.onFulfilledCallbacks.push((value) => {
            setTimeout(() => { // 因为要等待程序当前函数执行栈清空才能执行回调函数，所以通过setTimeout将回调加入任务队列
              try {
                resolvePromise(
                  resPromise,
                  realOnFulfilled(value),
                  resolve,
                  reject
                );
              } catch (e) {
                reject(e);
                return e;
              }
            });
          });
          this.onRejectedCallbacks.push((reason) => {
            setTimeout(() => {
              try {
                resolvePromise(
                  resPromise,
                  realOnRejected(reason),
                  resolve,
                  reject
                );
              } catch (e) {
                reject(e);
                return e;
              }
            });
          });
        });
        return resPromise;
      case this.FULFILLED:
        // promise 未来将会调用onfulfilled
        let resPromise2 = new MyPromise((resolve, reject) => {
          // 相比与PENDING状态，FULLFILLED状态的回调函数可以直接执行，所以直接通过setTimeout加入任务队列
          setTimeout(() => {
            try {
              resolvePromise(
                resPromise2,
                realOnFulfilled(this.result),
                resolve,
                reject
              );
            } catch (e) {
              reject(e);
              return e;
            }
          });
        });
        return resPromise2;
      case this.REJECTED:
        // promise 未来将会调用onrejected
        let resPromise3 = new MyPromise((resolve, reject) => {
          setTimeout(() => {
            try {
              resolvePromise(
                resPromise3,
                realOnRejected(this.result),
                resolve,
                reject
              );
            } catch (e) {
              reject(e);
              return e;
            }
          });
        });
        return resPromise3;
    }
  }
  catch(onrejected) {
    return this.then(undefined, onrejected);
  }
  static deferred() {
    let result = {};
    result.promise = new MyPromise((resolve, reject) => {
      result.resolve = resolve;
      result.reject = reject;
    });
    return result;
  }
}

//通过该函数对result进行解析，从而确定promise的转移状态以及需要传递的值，并在result解析完成后才执行promise的状态转移.
function resolvePromise(promise, result, resolve, reject) {
  // 循环引用检测
  if (promise === result) {
    return reject(new TypeError("循环引用"));
  }

  // 如果回调为promise实例，则继续对回调的结果进行解析
  if (result instanceof Promise) {
    result.then(function (newResult) {
      resolvePromise(promise, newResult, resolve, reject);
    }, reject);
  } else if (typeof result === "object" || typeof result === "function") {
    // 如果回调为对象或者函数
    if (result === null) {
      return resolve(result);
    }

    var then;
    try {
      then = result.then;
    } catch (error) {
      return reject(error);
    }

    if (typeof then === "function") {
      var called = false;
      try {
        var thenLock = function (fn) {
          if (called) return;
          called = true;
          fn && fn();
        };

        then.call(
          result,
          function (nextResult) {
            thenLock(function () {
              resolvePromise(promise, nextResult, resolve, reject);
            });
          },
          function (e) {
            thenLock(function () {
              reject(e);
            });
          }
        );
      } catch (error) {
        thenLock(function () {
          reject(error);
        });
      }
    } else {
      resolve(result);
    }
  } else {
    // 如果回调既不是promise又不是对象或函数
    resolve(result);
  }
}

module.exports = MyPromise;
